package net.zhongfu.flowable.helper.common.utils;

import liquibase.database.DatabaseFactory;
import liquibase.datatype.DataTypeFactory;
import net.zhongfu.flowable.helper.dataType.BooleanDataTypeDm;
import net.zhongfu.flowable.helper.dataType.DateTimeDataTypeForKingBaseEs;
import net.zhongfu.flowable.helper.database.DmDatabase;
import net.zhongfu.flowable.helper.database.HighGoDatabase;
import net.zhongfu.flowable.helper.database.KingBaseDatabase;
import org.flowable.common.engine.impl.AbstractEngineConfiguration;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;

public class DatabaseUtils {
    private static final Logger logger = LoggerFactory.getLogger(DatabaseUtils.class);
    private static final String DATABASE_TYPE_MAPPINGS="databaseTypeMappings";

    public static String getSchema(Connection connection, String productName) throws SQLException {
        DatabaseMetaData metaData = connection.getMetaData();
        if(productName.equalsIgnoreCase(metaData.getDatabaseProductName())) {
            // 适配数据库返回schema
            return connection.getSchema();
        }
        return null;
    }

    public static String getSchema(Connection connection, Set<String> productNames) throws SQLException {
        DatabaseMetaData metaData = connection.getMetaData();
        if(productNames.contains(metaData.getDatabaseProductName())) {
            return connection.getSchema();
        }
        return null;
    }


    public static String getProductName(Connection connection) throws SQLException {
        DatabaseMetaData metaData = connection.getMetaData();
        return metaData.getDatabaseProductName();
    }

    /**
     * 国产数据库类型注册，liquibase数据库管理使用
     * @param dataSource
     */
    public static void registrar(DataSource dataSource) {
        try {
            String productName = DatabaseUtils.getProductName(dataSource.getConnection());
            // 注册database
            if(DmDatabase.PRODUCT_NAME.equals(productName)) {
                DatabaseFactory.getInstance().register(new DmDatabase());
                DataTypeFactory.getInstance().unregister("boolean");
                DataTypeFactory.getInstance().register(BooleanDataTypeDm.class);
            } else if (KingBaseDatabase.PRODUCT_NAME.equals(productName)) {
                DatabaseFactory.getInstance().register(new KingBaseDatabase());
                DataTypeFactory.getInstance().unregister("datetime");
                DataTypeFactory.getInstance().register(DateTimeDataTypeForKingBaseEs.class);
            } else if (HighGoDatabase.PRODUCT_NAME.equals(productName)) {
                DatabaseFactory.getInstance().register(new HighGoDatabase());
                DataTypeFactory.getInstance().unregister("datetime");
//                DataTypeFactory.getInstance().register(DateTimeDataTypeForHighGoBase.class);
            }
        } catch (SQLException throwables) {
            logger.error("Flowable适配数据库错误,数据库类型注册失败",throwables);
        }
    }

    /**
     * Flowable扩展数据库类型
     * @param prEngineConfiguration
     * @param superclass
     */
    public static void databaseTypeExtend(SpringProcessEngineConfiguration prEngineConfiguration,Class<?> superclass) {
        if(Objects.isNull(prEngineConfiguration)||Object.class.equals(superclass)) {
            return;
        }
        if(superclass.equals(AbstractEngineConfiguration.class)) {
            try {
                Field declaredField = superclass.getDeclaredField(DATABASE_TYPE_MAPPINGS);
                declaredField.setAccessible(true);
                Properties properties = (Properties) declaredField.get(prEngineConfiguration);
                // 扩展数据库类型
                properties.setProperty(DmDatabase.PRODUCT_NAME, "oracle");
                properties.setProperty(KingBaseDatabase.PRODUCT_NAME, "postgres");
                properties.setProperty(HighGoDatabase.PRODUCT_NAME, "postgres");
                declaredField.set(prEngineConfiguration,properties);
                return;
            }catch (Exception ex) {
                logger.error("Flowable扩展数据库类型错误",ex);
            }
        }
        databaseTypeExtend(prEngineConfiguration,superclass.getSuperclass());
    }
}
